import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;

public class Game1024 extends JFrame {
    private static final int SIZE = 4;
    private static final int GRID_PADDING = 10;
    private static final int TILE_SIZE = 80;
    private static final int WINDOW_WIDTH = TILE_SIZE * SIZE + GRID_PADDING * (SIZE + 1);
    private static final int WINDOW_HEIGHT = TILE_SIZE * SIZE + GRID_PADDING * (SIZE + 1) + 100;

    private int[][] board;
    private boolean gameOver;
    private boolean win;
    private Random random;
    private JLabel scoreLabel;
    private int score;
    private TilePanel tilePanel;

    public Game1024() {
        board = new int[SIZE][SIZE];
        random = new Random();
        gameOver = false;
        win = false;
        score = 0;
        initBoard();
        initUI();
    }

    private void initBoard() {
        generateRandomNumber();
        generateRandomNumber();
    }

    private void generateRandomNumber() {
        int emptyCells = countEmptyCells();
        if (emptyCells == 0) return;

        int position = random.nextInt(emptyCells) + 1;
        int count = 0;
        int value = random.nextDouble() < 0.9 ? 2 : 4;

        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (board[i][j] == 0) {
                    count++;
                    if (count == position) {
                        board[i][j] = value;
                        return;
                    }
                }
            }
        }
    }

    private int countEmptyCells() {
        int count = 0;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (board[i][j] == 0) {
                    count++;
                }
            }
        }
        return count;
    }

    private void initUI() {
        setTitle("1024游戏");
        setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setResizable(false);

        // 设置全局字体支持中文
        Font chineseFont = new Font("SimHei", Font.PLAIN, 14);
        setChineseFont(this, chineseFont);

        setLayout(new BorderLayout());

        // 顶部面板
        JPanel topPanel = new JPanel();
        topPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 10));
        topPanel.setBackground(new Color(0xFAF8EF));

        JLabel titleLabel = new JLabel("1024");
        titleLabel.setFont(new Font("SimHei", Font.BOLD, 36));
        titleLabel.setForeground(new Color(0x776E65));
        topPanel.add(titleLabel);

        scoreLabel = new JLabel("分数: 0");
        scoreLabel.setFont(new Font("SimHei", Font.BOLD, 18));
        scoreLabel.setForeground(new Color(0x776E65));
        topPanel.add(scoreLabel);

        JButton newGameButton = new JButton("新游戏");
        newGameButton.setFont(new Font("SimHei", Font.BOLD, 14));
        newGameButton.setBackground(new Color(0x8F7A66));
        newGameButton.setForeground(Color.WHITE);
        newGameButton.setBorderPainted(false);
        newGameButton.setFocusPainted(false);
        newGameButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                resetGame();
            }
        });
        topPanel.add(newGameButton);

        add(topPanel, BorderLayout.NORTH);

        // 游戏面板
        tilePanel = new TilePanel();
        tilePanel.setBackground(new Color(0xBBADA0));
        add(tilePanel, BorderLayout.CENTER);

        // 键盘事件监听
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (gameOver || win) return;

                boolean moved = false;
                int[][] oldBoard = cloneBoard();

                switch (e.getKeyCode()) {
                    case KeyEvent.VK_UP:
                        moved = moveUp();
                        break;
                    case KeyEvent.VK_DOWN:
                        moved = moveDown();
                        break;
                    case KeyEvent.VK_LEFT:
                        moved = moveLeft();
                        break;
                    case KeyEvent.VK_RIGHT:
                        moved = moveRight();
                        break;
                    case KeyEvent.VK_W:
                        moved = moveUp();
                        break;
                    case KeyEvent.VK_S:
                        moved = moveDown();
                        break;
                    case KeyEvent.VK_A:
                        moved = moveLeft();
                        break;
                    case KeyEvent.VK_D:
                        moved = moveRight();
                        break;
                    default:
                        break;
                }

                if (moved) {
                    generateRandomNumber();
                    checkGameState();
                    tilePanel.repaint();
                    scoreLabel.setText("分数: " + score);
                }
            }
        });

        setFocusable(true);
    }

    // 递归设置所有组件的字体
    private void setChineseFont(Component component, Font font) {
        component.setFont(font);
        if (component instanceof Container) {
            for (Component child : ((Container) component).getComponents()) {
                setChineseFont(child, font);
            }
        }
    }


    private boolean moveUp() {
        boolean moved = false;
        for (int j = 0; j < SIZE; j++) {
            for (int i = 1; i < SIZE; i++) {
                if (board[i][j] != 0) {
                    int row = i;
                    while (row > 0 && board[row-1][j] == 0) {
                        board[row-1][j] = board[row][j];
                        board[row][j] = 0;
                        row--;
                        moved = true;
                    }
                    if (row > 0 && board[row-1][j] == board[row][j]) {
                        board[row-1][j] *= 2;
                        score += board[row-1][j];
                        board[row][j] = 0;
                        moved = true;
                    }
                }
            }
        }
        return moved;
    }

    private boolean moveDown() {
        boolean moved = false;
        for (int j = 0; j < SIZE; j++) {
            for (int i = SIZE-2; i >= 0; i--) {
                if (board[i][j] != 0) {
                    int row = i;
                    while (row < SIZE-1 && board[row+1][j] == 0) {
                        board[row+1][j] = board[row][j];
                        board[row][j] = 0;
                        row++;
                        moved = true;
                    }
                    if (row < SIZE-1 && board[row+1][j] == board[row][j]) {
                        board[row+1][j] *= 2;
                        score += board[row+1][j];
                        board[row][j] = 0;
                        moved = true;
                    }
                }
            }
        }
        return moved;
    }

    private boolean moveLeft() {
        boolean moved = false;
        for (int i = 0; i < SIZE; i++) {
            for (int j = 1; j < SIZE; j++) {
                if (board[i][j] != 0) {
                    int col = j;
                    while (col > 0 && board[i][col-1] == 0) {
                        board[i][col-1] = board[i][col];
                        board[i][col] = 0;
                        col--;
                        moved = true;
                    }
                    if (col > 0 && board[i][col-1] == board[i][col]) {
                        board[i][col-1] *= 2;
                        score += board[i][col-1];
                        board[i][col] = 0;
                        moved = true;
                    }
                }
            }
        }
        return moved;
    }

    private boolean moveRight() {
        boolean moved = false;
        for (int i = 0; i < SIZE; i++) {
            for (int j = SIZE-2; j >= 0; j--) {
                if (board[i][j] != 0) {
                    int col = j;
                    while (col < SIZE-1 && board[i][col+1] == 0) {
                        board[i][col+1] = board[i][col];
                        board[i][col] = 0;
                        col++;
                        moved = true;
                    }
                    if (col < SIZE-1 && board[i][col+1] == board[i][col]) {
                        board[i][col+1] *= 2;
                        score += board[i][col+1];
                        board[i][col] = 0;
                        moved = true;
                    }
                }
            }
        }
        return moved;
    }

    private void checkGameState() {
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (board[i][j] >= 1024) {
                    win = true;
                    JOptionPane.showMessageDialog(this, "恭喜你，获胜了!", "游戏结束", JOptionPane.INFORMATION_MESSAGE);
                    return;
                }
            }
        }

        if (countEmptyCells() > 0) {
            return;
        }

        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                int current = board[i][j];
                if (i > 0 && board[i-1][j] == current) return;
                if (i < SIZE-1 && board[i+1][j] == current) return;
                if (j > 0 && board[i][j-1] == current) return;
                if (j < SIZE-1 && board[i][j+1] == current) return;
            }
        }

        gameOver = true;
        JOptionPane.showMessageDialog(this, "游戏结束，再接再厉!", "游戏结束", JOptionPane.INFORMATION_MESSAGE);
    }

    private int[][] cloneBoard() {
        int[][] clone = new int[SIZE][SIZE];
        for (int i = 0; i < SIZE; i++) {
            System.arraycopy(board[i], 0, clone[i], 0, SIZE);
        }
        return clone;
    }

    private void resetGame() {
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                board[i][j] = 0;
            }
        }
        score = 0;
        gameOver = false;
        win = false;
        initBoard();
        tilePanel.repaint();
        scoreLabel.setText("分数: " + score);
    }

    private class TilePanel extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            // 绘制所有格子
            for (int i = 0; i < SIZE; i++) {
                for (int j = 0; j < SIZE; j++) {
                    int x = GRID_PADDING + j * (TILE_SIZE + GRID_PADDING);
                    int y = GRID_PADDING + i * (TILE_SIZE + GRID_PADDING);
                    int value = board[i][j];

                    // 设置格子颜色
                    Color bgColor = getTileColor(value);
                    g2d.setColor(bgColor);
                    g2d.fillRoundRect(x, y, TILE_SIZE, TILE_SIZE, 14, 14);

                    // 如果格子有数字，绘制数字
                    if (value != 0) {
                        String text = String.valueOf(value);
                        Font font = new Font("Arial", Font.BOLD, getFontSize(value));
                        g2d.setFont(font);
                        g2d.setColor(getTextColor(value));

                        // 计算文本居中位置
                        FontMetrics metrics = g2d.getFontMetrics(font);
                        int textWidth = metrics.stringWidth(text);
                        int textHeight = metrics.getHeight();
                        int textX = x + (TILE_SIZE - textWidth) / 2;
                        int textY = y + (TILE_SIZE + textHeight) / 2 - metrics.getDescent();

                        g2d.drawString(text, textX, textY);
                    }
                }
            }
        }

        private Color getTileColor(int value) {
            switch (value) {
                case 2: return new Color(0xEEE4DA);
                case 4: return new Color(0xEDE0C8);
                case 8: return new Color(0xF2B179);
                case 16: return new Color(0xF59563);
                case 32: return new Color(0xF67C5F);
                case 64: return new Color(0xF65E3B);
                case 128: return new Color(0xEDCF72);
                case 256: return new Color(0xEDCC61);
                case 512: return new Color(0xEDC850);
                case 1024: return new Color(0xEDC53F);
                default: return new Color(0xF3F0F0);
            }
        }

        private Color getTextColor(int value) {
            return value <= 4 ? new Color(0x776E65) : Color.WHITE;
        }

        private int getFontSize(int value) {
            return value < 100 ? 28 : value < 1000 ? 24 : 20;
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            Game1024 game = new Game1024();
            game.setVisible(true);
        });
    }
}